/*
 * Copyright 2010, 2011, 2012 mapsforge.org
 *
 * This program is free software: you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 */
package org.mapsforge.android.maps.gml;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.util.Collection;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.jibx.runtime.BindingDirectory;
import org.jibx.runtime.IBindingFactory;
import org.jibx.runtime.IMarshallingContext;
import org.jibx.runtime.IUnmarshallingContext;
import org.jibx.runtime.JiBXException;
import org.mapsforge.android.maps.overlay.Overlay;

import android.graphics.Paint;
import android.graphics.drawable.Drawable;

/**
 * @author art Abstract class that represents a JiBX gml binding. It can be implemented to accept various gml schema
 *         versions and it provides methods to parse valid gml files and to obtain Overlays from it.
 */
public abstract class GMLBinding {

	/**
	 * The Logger Used For Logging purposes.
	 */
	public static final Logger LOGGER = Logger.getLogger(GMLBinding.class.getName());
	/**
	 * Initial Size of the collection that parseGML returns.
	 */
	public static final int INITIAL_CAPACITY = 2;

	/**
	 * Default Marker Style.
	 */
	protected Drawable defaultItemMarker = null;
	/**
	 * Default Polygon Paint Fill Style.
	 */
	protected Paint defaultPolyPaintFill = null;
	/**
	 * Default Polygon Paint Outline Style.
	 */
	protected Paint defaultPolyPaintOutline = null;
	/**
	 * Default Line Paint Fill Style.
	 */
	protected Paint defaultLinePaintFill = null;
	/**
	 * Default Line Paint Outline Style.
	 */
	protected Paint defaultLinePaintOutline = null;

	/**
	 * This is the File that has been last parsed. We store that in order to improve performance of the binding.
	 */
	protected File cachedFile = null;

	/**
	 * Encoding used by the JiBX marshaling.
	 */
	public static final String STRING_ENCODING = "UTF8";

	/**
	 * Encoding used by the JiBX marshaling.
	 */
	public static final String URL_ENCODING = "UTF-8";

	/**
	 * @return The string representing the subclass instance's concrete JiBx binding name
	 */
	protected abstract String getBindingName();

	/**
	 * @return The string representing the subclass instance's concrete JiBx binding package name
	 */
	protected abstract String getBindingPackage();

	/**
	 * @param gmlFile
	 *            is a gmlFile
	 * @return true if the file is a valid gml for this binding, false otherwise
	 */
	public abstract boolean isValidGML(File gmlFile);

	/**
	 * Parses a GML file using a JiBX binding to Java classes and fills a Collection of overlays containing its
	 * placemarks.
	 * 
	 * @param gmlFile
	 *            is a valid gml file to be parsed.
	 * @return a collection of overlays that can be added to a GMLOverlay instance.
	 * @throws FileNotFoundException
	 *             if the gmlFile is not found.
	 * @throws JiBXException
	 *             if the gmlFile can't be parsed using this binding implementation
	 */
	public abstract Collection<? extends Overlay> parseGML(File gmlFile) throws FileNotFoundException, JiBXException;

	/**
	 * This is like the reverse operation to parseGML. Given a Overlay collection it tries to create a GML with the
	 * appropriate features using the JiBX marshaling.
	 * 
	 * @param features
	 *            a collection of overlays.
	 * @return a string containing the marshaled gml
	 */
	public abstract String composeGML(Collection<? extends Overlay> features);

	/**
	 * Marshal this message to xml .
	 * 
	 * @param message
	 *            the object to marshal to xml .
	 * @return a String containing the marshaled xml
	 */
	public String marshalMessage(Object message) {
		try {
			IBindingFactory jc = BindingDirectory.getFactory(getBindingName(), getBindingPackage());
			IMarshallingContext marshaller = jc.createMarshallingContext();
			marshaller.setIndent(4);
			ByteArrayOutputStream out = new ByteArrayOutputStream();
			marshaller.marshalDocument(message, URL_ENCODING, null, out);
			return out.toString(STRING_ENCODING);
		} catch (UnsupportedEncodingException e) {
			LOGGER.log(Level.SEVERE, null, e);
		} catch (JiBXException e) {
			LOGGER.log(Level.SEVERE, null, e);
		}
		return null;
	}

	/**
	 * Unmarshal this xml Message to an object.
	 * 
	 * @param xml
	 *            the xml to marshal into Java Objects passed as a String
	 * @return the Java object mapped by JiBX that holds the xml information
	 */
	public Object unmarshalMessage(String xml) {
		try {
			IBindingFactory jc = BindingDirectory.getFactory(getBindingName(), getBindingPackage());
			IUnmarshallingContext unmarshaller = jc.createUnmarshallingContext();
			return unmarshaller.unmarshalDocument(new StringReader(xml), getBindingName());
		} catch (JiBXException e) {
			LOGGER.log(Level.SEVERE, null, e);
		}
		return null;
	}

}
